﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using EnvDTE;
using Soat.SoPrism.TemplateWizards.Helpers;
using Soat.SoPrism.TemplateWizards.Properties;

namespace Soat.SoPrism.TemplateWizards
{
    /// <summary>
    /// Cette classe représente un Wizard permettant d'ajouter les items d'un template de solution en items de Solution
    /// </summary>
    public class SolutionWizard : ProjectWizard
    {
        #region Consts

        /// <summary>
        /// Time pour le UnLock des fichiers par VS2010
        /// </summary>
        const int MIN_TIME_FOR_PROJECT_TO_RELEASE_FILE_LOCK = 3000;

        #endregion

        private Dictionary<string, string> referenceFolderDictionary;

        #region ProjectFinishedGenerating Method

        /// <summary>
        /// Runs custom wizard logic when a project item has finished generating.
        /// </summary>
        /// <param name="project">The project item that finished generating.</param>
        public override void ProjectFinishedGenerating(Project project)
        {
            // Ajout des items venant de la solution (VsTemplate Solution)
            var content = this.WizardTemplateHelper.ReadDocument(this.VSTemplateFilename);
            var elementRoot = content.Root.Element(Resources.VSTEMPLATE_NAMESPACE + "TemplateContent").Element(Resources.VSTEMPLATE_NAMESPACE + "ProjectCollection");
            var folder = this.WizardDTEHelper.GetTargetSolutionFolder((EnvDTE.SolutionClass)(this.WizardParameterHelper.Globals).DTE.Solution) + "\\";
            var referenceProj = this.WizardDTEHelper.GetReferencesProject((EnvDTE.SolutionClass)(this.WizardParameterHelper.Globals).DTE.Solution);

            // Copie des fichiers issus du Template 
            var fileInfo = new FileInfo(this.VSTemplateFilename);
            if (File.Exists(fileInfo.Directory + "\\" + Resources.SOLUTION_FOLDER_FILENAME))
            {
                this.referenceFolderDictionary = new Dictionary<string, string>();
                XDocument ReferenceFolderDocument = XDocument.Load(fileInfo.Directory + "\\" + Resources.SOLUTION_FOLDER_FILENAME);
                foreach (var item in ReferenceFolderDocument.Root.Elements("Reference"))
                {
                    this.referenceFolderDictionary.Add(item.Attribute("PhysicalFolder").Value, item.Attribute("SolutionFolder").Value);
                }

                var referenceFolders = fileInfo.Directory.GetDirectories(Resources.REFERENCE_DIRECTORY);
                if (referenceFolders.Length > 0)
                {
                    var referenceFolder = referenceFolders[0];
                    this.AddReferences(referenceFolder, new DirectoryInfo(folder + Resources.REFERENCE_SOLUTION_FOLDER), referenceProj);
                }
            };

            // TODO ! Réaffecte le Guid du Project Application Silverlight à l'Application Web
            // this.ChangeReferenceSilverlightProject();
            // this.SelectWebProject();

        }

        #endregion
        
        #region SelectWebProject Method
        
        /// <summary>
        /// Cette méthode permet de sélectionner le projet Web.
        /// </summary>
        private void SelectWebProject()
        {
            var websiteProject = this.WizardDTEHelper.GetTargetProject((EnvDTE.SolutionClass)(this.WizardParameterHelper.Globals).DTE.Solution, "WebSite.csproj");
            var solutionExplorer = ((UIHierarchy)(this.WizardParameterHelper.Globals).DTE.ActiveWindow.Object);

            EnvDTE.UIHierarchyItem hierarchyItem = this.WizardDTEHelper.FindHierarchyItem(solutionExplorer.UIHierarchyItems, websiteProject.ParentProjectItem);
            if (hierarchyItem != null)
            {
                hierarchyItem.Select(EnvDTE.vsUISelectionType.vsUISelectionTypeSelect);
                (this.WizardParameterHelper.Globals).DTE.ExecuteCommand("ClassViewContextMenus.ClassViewMultiselectProjectreferencesItems.Properties");
            }
        } 

        #endregion

        #region ChangeReferenceSilverlightProject Method (Non Fonctionnel !)

        /// <summary>
        /// Cette méthode permet de réaffecter le Projet Silverlight au projet Web car les Guid sont créer par Visual Studio
        /// </summary>
        private void ChangeReferenceSilverlightProject()
        {
            var coreProject = this.WizardDTEHelper.GetTargetProject((EnvDTE.SolutionClass)(this.WizardParameterHelper.Globals).DTE.Solution, "Core.csproj");
            var websiteProject = this.WizardDTEHelper.GetTargetProject((EnvDTE.SolutionClass)(this.WizardParameterHelper.Globals).DTE.Solution, "WebSite.csproj");
            if (coreProject != null && websiteProject != null)
            {
                //(this.WizardParameterHelper.Globals).DTE.Solution.SaveAs(this.ReplacementsDictionary["$dataname$"] + ".sln");

                // La sauvegarde permet à Visual Studio de recréer les Guid Projet !!
                coreProject.Save();
                websiteProject.Save();
                var webSiteFilename = websiteProject.FileName;

                var solutionExplorer = ((UIHierarchy)(this.WizardParameterHelper.Globals).DTE.ActiveWindow.Object);

                EnvDTE.UIHierarchyItem hierarchyItem = this.WizardDTEHelper.FindHierarchyItem(solutionExplorer.UIHierarchyItems, websiteProject.ParentProjectItem);
                if (hierarchyItem != null)
                {
                    hierarchyItem.Select(EnvDTE.vsUISelectionType.vsUISelectionTypeSelect);
                }

                // Supprime le projet venant d'être ajouté
                (this.WizardParameterHelper.Globals).DTE.Solution.Remove(websiteProject);

                System.Threading.Thread.Sleep(MIN_TIME_FOR_PROJECT_TO_RELEASE_FILE_LOCK);
                
                //"ClassViewContextMenus.ClassViewMultiselectProjectreferencesItems.Properties"

                //    //(this.WizardParameterHelper.Globals).DTE.ExecuteCommand("Project.UnloadProject");

                // Récupération du nouveau Guid et affectation au projet WebSite
                var coreProjectDocument = this.WizardTemplateHelper.ReadDocument(webSiteFilename);
                var projectGuidELement = coreProjectDocument.Root.Elements(Resources.MSBUILD_NAMESPACE + "PropertyGroup").Elements(Resources.MSBUILD_NAMESPACE + "ProjectGuid").FirstOrDefault();
                if (projectGuidELement != null)
                {
                    //projectGuidELement.Value;
                    var websiteProjectDocument = this.WizardTemplateHelper.ReadDocument(webSiteFilename);
                    var silverlightProjectGuidELement = websiteProjectDocument.Root.Elements(Resources.MSBUILD_NAMESPACE + "PropertyGroup").Elements(Resources.MSBUILD_NAMESPACE + "SilverlightApplicationList").FirstOrDefault();
                    if (silverlightProjectGuidELement != null)
                    {
                        // Remplacement de l'identifiant de l'application Silverlight Core
                        silverlightProjectGuidELement.Value = projectGuidELement.Value + silverlightProjectGuidELement.Value.Remove(0, 38); // Taille d'un Guid
                        websiteProjectDocument.Save(websiteProject.FileName);
                    }
                }

                // Ajout à la solution du fichier Project renommé
                (this.WizardParameterHelper.Globals).DTE.Solution.AddFromFile(webSiteFilename, false);

            }
            //    //(this.WizardParameterHelper.Globals).DTE.ExecuteCommand("Project.ReloadProject");
            //}
        }

        #endregion

        #region AddReferences Method

        /// <summary>
        /// Cette méthode permet d'ajouter les références (Assemblies .dll) dans le répertoire de solution "_References"
        /// </summary>
        /// <param name="sourceFolder">Répertoire Physique source venant du vstemplate</param>
        /// <param name="targetFolder">Répertoire de solution cible après génération</param>
        /// <param name="projFolder">Objet répertoire de solution (ou sous répertoire de solution)</param>
        private void AddReferences(DirectoryInfo sourceFolder, DirectoryInfo targetFolder, Project projFolder)
        {
            foreach (var item in sourceFolder.GetFiles())
            {
                // Copie des fichiers dans le répertoire
                File.Copy(item.FullName, targetFolder.FullName + "\\" + item.Name);

                // Ajout du fichier au ProjectItem
                var projItem = projFolder.ProjectItems.AddFromFile(targetFolder.FullName + "\\" + item.Name);

                // Fermeture de la fenetre VS
                ((EnvDTE._DTE)(projItem.DTE)).Documents.Item(1).Close();
            }

            foreach (var subFolder in sourceFolder.GetDirectories())
            {
                if (this.referenceFolderDictionary.ContainsKey(subFolder.Name))
                {
                    // recupere le ProjectItem associé 
                    for (int i = 1; i <= projFolder.ProjectItems.Count; i++)
                    {
                        if (projFolder.ProjectItems.Item(i).Name.Equals(this.referenceFolderDictionary[subFolder.Name], StringComparison.InvariantCultureIgnoreCase))
                        {
                            // Parcours des sous-répertoire
                            this.AddReferences(subFolder, new DirectoryInfo(targetFolder.FullName + "\\" + this.referenceFolderDictionary[subFolder.Name]), projFolder.ProjectItems.Item(i).SubProject);
                        }
                    }
                }
            }
        }

        #endregion

        #region InitializeDictionary Method

        /// <summary>
        /// Cette méthode permet d'initialiser l'ensemble des variables en sessions dans Visual Studio
        /// </summary>
        /// <param name="replacementsDictionary">Parametres de remplacement</param>
        public override void InitializeDictionary(Dictionary<string, string> replacementsDictionary)
        {
            for (int i = 1; i < 80; i++)
            {
                if (!replacementsDictionary.ContainsKey(string.Format("$guid{0}$", i)))
                {
                    replacementsDictionary.Add(string.Format("$guid{0}$", i), Guid.NewGuid().ToString());
                }
                this.WizardParameterHelper.SetParameterValue(string.Format("$guid{0}$", i), replacementsDictionary[string.Format("$guid{0}$", i)]);
            }

            // $dataname$ correspond a la valeur saisie par l'utilisateur
            if (!replacementsDictionary.ContainsKey("$dataname$"))
            {
                replacementsDictionary.Add("$dataname$", replacementsDictionary["$projectname$"]);
            }
            this.WizardParameterHelper.SetParameterValue("$dataname$", replacementsDictionary["$projectname$"]);

            base.InitializeDictionary(replacementsDictionary);
        }

        #endregion
    }
}
